package com.mspbots.attendance.trigger;


import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mspbots.api.client.CoreClient;
import com.mspbots.api.client.TeamsClient;
import com.mspbots.attendance.mapper.TenantAttendanceMapper;
import com.mspbots.attendance.model.TenantUserWorkScheduleDTO;
import com.mspbots.attendance.request.TenantDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class AttendanceOutCheckTriggerEvent {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private CoreClient coreClient;

    @Autowired
    private TeamsClient teamsClient;

    @Autowired
    private TenantAttendanceMapper tenantAttendanceMapper;

    private static final String REDIS_KEY_PREFIX_TENANT = "MSPBOTS:CONFIG:TENANT:";

//    @Scheduled(initialDelay = 10000, fixedRate = 60 * 1000)
    @Scheduled(initialDelay = 10000, fixedRateString = "${mspbots.fixedDelay.outCheck}")
    public void produce() {
        log.debug("attendance outCheck...");
        List tenants = this.redisTemplate.opsForList().range(REDIS_KEY_PREFIX_TENANT + "tenants", 0, -1);
        log.debug("tenants ...  {}", tenants);
        List<TenantDTO> tenantDTOS = objectMapper.convertValue(tenants, new TypeReference<List<TenantDTO>>() {
        });
        log.debug("tenantDTOS ...  {}", tenantDTOS);
        tenantDTOS.stream().filter(item -> item.getStatusId() == 1).forEach(tenantDTO -> {
            JsonNode userWorkSchedule = coreClient.get("/user-work-schedule/findUserSchedule/" + tenantDTO.getId()).block();
            List<TenantUserWorkScheduleDTO> tenantUserWorkScheduleDTO = objectMapper.convertValue(userWorkSchedule, new TypeReference<List<TenantUserWorkScheduleDTO>>() {
            });
            log.debug("tenantUserWorkScheduleDTO ... {}, {}", tenantDTO.getId(),tenantUserWorkScheduleDTO.size());
            tenantUserWorkScheduleDTO.parallelStream().forEach(schedule -> {
                ZonedDateTime zonedTimeNow = ZonedDateTime.now(ZoneId.of(schedule.getTimezoneOffset()));
                DayOfWeek dayOfWeek = zonedTimeNow.getDayOfWeek();
                schedule.getWorkScheduleList().stream().filter(item ->
                        item.getDayOfWeek().equals(dayOfWeek.name())).forEach(workTime -> {
                    log.debug("workTime ...  {}", workTime);
                    LocalTime beginTime = workTime.getBeginTime();
                    LocalTime endTime = workTime.getEndTime();
                    if (StringUtils.isEmpty(beginTime) || StringUtils.isEmpty(endTime)) {
                        log.info("beginTime or endTime is null ...  {}", workTime);
                        return;
                    }

                    ZonedDateTime zonedStartTimeWork = ZonedDateTime.of(zonedTimeNow.toLocalDate(), beginTime, ZoneId.of(schedule.getTimezoneOffset()));
                    ZonedDateTime zonedEndTimeWork = ZonedDateTime.of(zonedTimeNow.toLocalDate(), endTime, ZoneId.of(schedule.getTimezoneOffset()));

                    if(!ObjectUtils.isEmpty(schedule.getTenantUserId())) {

                        log.debug("getTenantUserId ...  {}", schedule.getTenantUserId());
                        Map<String, Object> params = Map.of(
                                "tenantId", schedule.getTenantId(),
                                "tenantUserId", schedule.getTenantUserId()
                        );
                        JsonNode userMapping = coreClient.get("/user-mapping/detail", params).block();

                        if (!ObjectUtils.isEmpty(userMapping)) {

                            log.debug("userMapping ...  {}", userMapping);

                            LocalDateTime holiday1 = LocalDateTime.parse("2020-05-25 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                            LocalDateTime holiday2 = LocalDateTime.parse("2020-07-04 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                            LocalDateTime holiday3 = LocalDateTime.parse("2020-09-07 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

                            if (!(LocalDateTime.now().getDayOfYear() == holiday1.getDayOfYear())
                                    ||!(LocalDateTime.now().getDayOfYear() == holiday2.getDayOfYear())
                                    ||!(LocalDateTime.now().getDayOfYear() == holiday3.getDayOfYear())) {



                                JsonNode paramValue = tenantAttendanceMapper.selectOutCheckTime(userMapping.get("tenantId").asLong());

                                log.debug("paramValue ...  {}", paramValue);
                                Integer mins = 10;
                                if(!paramValue.isEmpty() && paramValue.has("minutes")){
                                    mins = paramValue.get("minutes").asInt();
                                }

                                if (zonedStartTimeWork != null) {
                                    log.debug("zonedStartTimeWork ...  {}", zonedStartTimeWork);
                                    String key = "outcheck:"+zonedEndTimeWork.getYear()+":"+zonedEndTimeWork.getMonthValue()+":"+zonedEndTimeWork.getDayOfMonth()+":"+userMapping.get("teamsUserId").asText();
                                    log.debug("redis key ...  {}", this.redisTemplate.opsForValue().get(key));
                                    if(ObjectUtils.isEmpty(this.redisTemplate.opsForValue().get(key))){
                                        log.info("zonedTimeNow time compore...  {}", zonedTimeNow.isAfter(zonedEndTimeWork.minusMinutes(mins)) && zonedTimeNow.isBefore(zonedEndTimeWork));
                                        if (zonedTimeNow.isAfter(zonedEndTimeWork.minusMinutes(mins)) && zonedTimeNow.isBefore(zonedEndTimeWork)) {
                                            log.info("zonedTimeNow  ...  {}", zonedTimeNow);
                                            Map<String, Object> paramCommand = new HashMap<String, Object>();
                                            paramCommand.put("teamsUserId", userMapping.get("teamsUserId").asText());
                                            paramCommand.put("message", "Stats");
                                            paramCommand.put("tenantId", userMapping.get("tenantId").asLong());
                                            paramCommand.put("sync", false);
                                            paramCommand.put("fromType", "endOfDayBefore");
                                            JsonNode commandResult = teamsClient.post("/message/command", paramCommand).block();
                                            log.info("attendance log teamsClient:commandResult: {}", commandResult);
                                            this.redisTemplate.opsForValue().set(key,"1",Duration.ofHours(20));
                                        }
                                    }else{
                                        log.debug("redis key ...  {},{}", key,"is not 1");

                                    }
                                }
                            }
                        }
                    }
                });
            });
        });


    }
}
